import {confirm, replace, util} from "./util.ts";
import {DataTableSortState, NButton, NSpace} from "naive-ui";
import post from "../axios";
import {h} from "vue";

export interface IInput {
    label: string
    path: string
    offset?: number
    span?: number

    disabled?: boolean
    showButton?: boolean
    minLength?: number
    maxLength?: number
    precision?: number
    defaultValue?: null | string | number | Date | Array<string | number | Date>
    clearable?: boolean
    placeholder?: string
    readonly?: boolean

    exist?: boolean
    inputType?: 'text' | 'number' | 'select' | 'date' | 'datetime' | 'dateRange' | 'datetimeRange' | 'radio' | 'checkbox' | 'transfer' | 'tag'
    options?: Array<any>
    optionsUrl?: string
    optionsParams?: any

    style: string
}

export class BaseInput implements IInput {
    label: string
    path: string
    offset: number = 0
    span: number = 6

    disabled: boolean = false
    showButton: boolean = false
    minLength: number = 0
    maxLength: number = 999999
    precision: number = 0
    defaultValue: null | string | number | Date | Array<string | number | Date> = null
    clearable: boolean = true
    placeholder: string = ''
    readonly: boolean = false

    exist: boolean = true
    inputType: 'text' | 'number' | 'select' | 'date' | 'datetime' | 'dateRange' | 'datetimeRange' | 'radio' | 'checkbox' | 'transfer' | 'tag' = 'text'
    options: Array<any> = []
    optionsUrl: string = ''
    optionsParams: any = {}

    style: string = 'width: 100%'

    constructor(label: string, path: string) {
        this.label = label
        this.path = path
    }
}

export interface IColumn {
    exist?: boolean
    key: string
    title: string
    titleAlign?: 'left' | 'center' | 'right'
    align?: 'left' | 'center' | 'right'
    width?: string | number
    sorter?: string | boolean | null
    defaultSortOrder?: string | null
    ellipsis?: boolean | { tooltip: boolean }
    render?: null | Function
}

export class BaseColumn implements IColumn {
    exist?: boolean = true
    key: string
    title: string
    titleAlign?: 'left' | 'center' | 'right' = 'center'
    align?: 'left' | 'center' | 'right' = 'center'
    width?: string | number = 'auto'
    sorter?: string | boolean | null = null
    defaultSortOrder?: string | null = 'descend'
    ellipsis?: boolean | { tooltip: boolean } = {tooltip: true}
    render?: null | Function = null

    constructor(key: string, title: string) {
        this.key = key
        this.title = title
    }
}

export interface IButton {
    block?: boolean
    bordered?: boolean
    circle?: boolean
    color?: string
    dashed?: boolean
    disabled?: boolean
    ghost?: boolean
    loading?: boolean
    round?: boolean
    size?: 'tiny' | 'small' | 'medium' | 'large'
    textColor?: string
    type?: 'default' | 'tertiary' | 'primary' | 'success' | 'info' | 'warning' | 'error'

    exist?: boolean
    text: string
    confirmClick?: boolean
    click: Function
}

export class BaseButton implements IButton {
    block: boolean = false
    bordered: boolean = false
    circle: boolean = false
    color: string = ''
    dashed: boolean = false
    disabled: boolean = false
    ghost: boolean = false
    loading: boolean = false
    round: boolean = false
    size: 'tiny' | 'small' | 'medium' | 'large' = 'small'
    textColor: string = ''
    type: 'default' | 'tertiary' | 'primary' | 'success' | 'info' | 'warning' | 'error' = 'default'

    exist: boolean = true
    text: string
    confirmClick: boolean = false
    click: Function

    constructor(text: string, click: Function) {
        this.text = text
        this.click = click
    }
}

export interface Rule {
    type?: string,
    required: boolean
    message?: string
    pattern?: '' | null
    trigger?: Array<string>
    validator?: null | Function
}

export class BaseRule implements Rule {
    type: string = 'string'
    required: boolean = true
    message: string = '请检查输入'
    pattern: '' | null = null
    trigger: Array<string> = ['blur']
    validator: null | Function = null
}

export interface IPage {
    search: BaseModel
    leftOperations: Array<BaseButton>
    rightOperations: Array<BaseButton>
    columns: Array<BaseColumn>
    operationColumn: BaseColumn
    operationColumnExtOperation: Array<BaseButton>
    data: Array<any>
    pagination: Pagination
    checkedRowKeys: Array<string | number>
    loading: boolean
    url: {
        save: string
        updateById: string
        deleteById: string
        selectById: string
        selectPage: string
    }
    changeSort: Function
    loadData: Function
    models: Array<BaseModel>
    currentModel: BaseModel
    bind: Function
    options: any
    loadOptions: Function
}

export class BasePage implements IPage {
    search: BaseModel = new BaseModel('', '', [], [], this)
    leftOperations: Array<BaseButton> = new Array<BaseButton>()
    rightOperations: Array<BaseButton> = new Array<BaseButton>()
    columns: Array<BaseColumn> = new Array<BaseColumn>()
    operationColumn: BaseColumn = new BaseColumn('operation', '操作')
    operationColumnExtOperation: Array<BaseButton> = new Array<BaseButton>()
    data: Array<any> = new Array<any>()
    pagination: Pagination = new Pagination(this)
    checkedRowKeys: Array<string | number> = new Array<string | number>()
    loading: boolean = false
    url: {
        save: string
        updateById: string
        deleteById: string
        selectById: string
        selectPage: string
    } = {
        save: '',
        updateById: '',
        deleteById: '',
        selectById: '',
        selectPage: ''
    }
    models: Array<BaseModel> = new Array<BaseModel>()
    currentModel: BaseModel = new BaseModel('', '', [], [], this)
    options: any = {}

    changeSort: Function = () => {
    }

    loadData: Function = () => {
    }

    bind: Function = () => {
    }

    loadOptions: Function = () => {

    }
}

export interface IPagination {
    desc?: boolean
    itemCount?: number
    page?: number
    pageSize?: number
    showSizePicker?: boolean
    showQuickJumper?: boolean
    pageSizes?: Array<number>
    onUpdatePage?: Function
    onUpdatePageSize?: Function
}

export class Pagination implements IPagination {
    desc: boolean = true
    itemCount: number = 0
    page: number = 1
    pageSize: number = 10
    showSizePicker: boolean = true
    showQuickJumper: boolean = true
    pageSizes: Array<number> = [10, 20, 50, 100]
    onUpdatePage: Function
    onUpdatePageSize: Function

    constructor(basePage: IPage) {
        this.onUpdatePage = (page: number) => {
            this.page = page
            basePage.loadData()
        }
        this.onUpdatePageSize = (pageSize: number) => {
            this.pageSize = pageSize
            basePage.loadData()
        }
    }

}

export let completePage = (page: BasePage): IPage => {
    page.search = new BaseModel('search', '查询', [], [], page)
    let searchBtn = new BaseButton('查询', () => {
        page.loadData()
    })
    searchBtn.type = 'primary'
    page.leftOperations.push(searchBtn)
    let resetBtn = new BaseButton('重置', () => {
        page.search.formReset()
    })
    page.leftOperations.push(resetBtn)
    let moreBtn = replace(new BaseButton('展示更多', () => {
        page.currentModel = page.models.filter(m => 'moreColumn' == m.formKey)[0]
        page.currentModel.formReset()
        page.currentModel.exist = true
    }), {
        type: 'info'
    })
    page.leftOperations.push(moreBtn)
    let addBtn = new BaseButton('新增', () => {
        page.currentModel = page.models.filter(m => 'save' == m.formKey)[0]
        page.currentModel.formReset()
        page.currentModel.exist = true
    })
    addBtn.type = 'success'
    page.rightOperations.push(addBtn)

    let operationColumn = new BaseColumn('operation', '操作')
    operationColumn.render = (row: any) => {
        return h(
            NSpace,
            {
                justify: 'center'
            },
            {
                default: () => {
                    let updateBtn = new BaseButton('修改', () => {
                        page.currentModel = page.models.filter(m => 'update' == m.formKey)[0]
                        page.currentModel.formReset()
                        page.currentModel.exist = true
                        post(page.url.selectById, {id: row.id}).then((res: any) => {
                            page.currentModel.model = res
                        })
                    })
                    updateBtn.type = 'warning'
                    let deleteBtn = new BaseButton('删除', () => {
                        post(page.url.deleteById, {id: row.id}).then((res: any) => {
                            page.currentModel.model = res
                            page.loadData()
                        })
                    })
                    deleteBtn.confirmClick = true
                    deleteBtn.type = 'error'
                    let detailBtn = new BaseButton('详情', () => {
                        page.currentModel = page.models.filter(m => 'detail' == m.formKey)[0]
                        page.currentModel.formReset()
                        page.currentModel.exist = true
                        post(page.url.selectById, {id: row.id}).then((res: any) => {
                            page.currentModel.model = res
                        })
                    })


                    return [
                        renderBtn(updateBtn, row),
                        renderBtn(deleteBtn, row),
                        renderBtn(detailBtn, row),
                        ...page.operationColumnExtOperation.map(
                            btn => renderBtn(btn, row)
                        )
                    ]
                }
            }
        )
    }
    page.operationColumn = operationColumn

    page.pagination = new Pagination(page)
    page.changeSort = (options: DataTableSortState) => {
        if (options.order === false) options.order = "descend"
        page.pagination.desc = options.order === "descend"
        page.loadData()
    }
    page.loadData = () => {
        page.loading = true
        post(page.url.selectPage, Object.assign({}, page.pagination, page.search.model)).then((res: any) => {
            page.data = []
            if (res.list) {
                for (let i = 0; i < res.list.length; i++) {
                    page.data.push(Object.assign({}, res.list[i], {index: i + 1}))
                }
            }
            page.pagination.itemCount = res.total
        }).finally(() => {
            page.loading = false
        })
        page.loadOptions()
    }
    page.bind = (el: any) => {
        if (page.currentModel && el) {
            page.currentModel.formRef = el
        }
    }

    let saveBtn = new BaseButton('保存', () => {
        page.currentModel.formRef?.validate((errors: any) => {
            if (errors) {
                util.msg?.error('请检查填写内容')
            } else {
                post(page.url.save, page.currentModel.model).then(() => {
                    util.msg?.success('保存成功')
                    page.currentModel.exist = false
                    page.loadData()
                })
            }
        })
    })
    saveBtn.type = 'primary'

    let cancelBtn = new BaseButton('取消', () => {
        page.currentModel.exist = false
    })
    let saveModel = new BaseModel('save', '新增', [], [
        saveBtn,
        cancelBtn
    ], page)

    let updateBtn = new BaseButton('保存', () => {
        page.currentModel.formRef?.validate((errors: any) => {
            if (errors) {
                util.msg?.error('请检查填写内容')
            } else {
                post(page.url.updateById, page.currentModel.model).then(() => {
                    util.msg?.success('更新成功')
                    page.currentModel.exist = false
                    page.loadData()
                })
            }
        })
    })
    saveBtn.type = 'primary'
    let updateModel = new BaseModel('update', '修改', [], [
        updateBtn,
        cancelBtn
    ], page)
    let detailModel = new BaseModel('detail', '详情', [], [
        cancelBtn
    ], page)
    let columnKeyInput = new BaseInput('所有展示列', 'columnKeys')
    columnKeyInput.span = 24
    columnKeyInput.inputType = 'checkbox'
    let updateColumnShowBtn = new BaseButton("查看", () => {
        page.columns
            .filter(c => c.key !== 'index')
            .filter(c => c.key !== 'id')
            .filter(c => c.key !== 'operation')
            .forEach(c => {
                c.exist = page.currentModel.model.columnKeys.includes(c.key)
            })
        page.currentModel.exist = false
    })
    let moreColumnModel = new BaseModel('moreColumn', '所有可展示列', [
        columnKeyInput
    ], [
        updateColumnShowBtn,
        cancelBtn
    ], page)
    moreColumnModel.formReset = () => {
        columnKeyInput.defaultValue = page.columns
            .filter(c => c.key !== 'index')
            .filter(c => c.key !== 'id')
            .filter(c => c.key !== 'operation')
            .filter(c => c.exist)
            .map(c => c.key)
        columnKeyInput.options = page.columns
            .filter(c => c.key !== 'index')
            .filter(c => c.key !== 'id')
            .filter(c => c.key !== 'operation')
            .map(c => {
                return {
                    label: c.title,
                    value: c.key
                }
            })
        moreColumnModel.model.columnKeys = columnKeyInput.defaultValue
    }

    page.models = [
        saveModel,
        updateModel,
        detailModel,
        moreColumnModel
    ]

    page.loadOptions = () => {
        page.search.formInputs
            .filter(i => i.inputType === 'select')
            .forEach(i => {
                if (i.options.length == 0 || i.options[0].label === '加载中') {
                    if (page.options[i.path]) {
                        i.options = page.options[i.path]
                    } else {
                        page.options[i.path] = [{
                            label: '加载中',
                            value: ''
                        }]
                        post(i.optionsUrl, i.optionsParams).then((res: any) => {
                            page.options[i.path] = res
                            page.loadOptions()
                        })
                    }
                } else {
                    i.options = page.options[i.path]
                }
            })
        page.models.forEach(m => {
            m.formInputs
                .filter(i => i.inputType === 'select')
                .forEach(i => {
                    if (i.options.length == 0 || i.options[0].label === '加载中') {
                        if (page.options[i.path]) {
                            i.options = page.options[i.path]
                        } else {
                            page.options[i.path] = [{
                                label: '加载中',
                                value: ''
                            }]
                            post(i.optionsUrl, i.optionsParams).then((res: any) => {
                                page.options[i.path] = res
                                page.loadOptions()
                            })
                        }
                    } else {
                        i.options = page.options[i.path]
                    }
                })
        })
    }

    return page;
}

export let renderBtn = (baseButton: BaseButton, params?: any) => {
    if (baseButton.confirmClick) {
        return h(
            NButton,
            {
                onClick: () => {
                    confirm('确定吗？', () => {
                        baseButton.click(params)
                    })
                },
                type: baseButton.type,
                color: baseButton.color,
                textColor: baseButton.textColor,
                block: baseButton.block,
                bordered: baseButton.bordered,
                circle: baseButton.circle,
                dashed: baseButton.dashed,
                disabled: baseButton.disabled,
                ghost: baseButton.ghost,
                loading: baseButton.loading,
                round: baseButton.round,
                size: baseButton.size
            },
            {
                default: () => baseButton.text
            }
        )
    } else {
        return h(
            NButton,
            {
                onClick: () => {
                    baseButton.click(params)
                },
                type: baseButton.type,
                color: baseButton.color,
                textColor: baseButton.textColor,
                block: baseButton.block,
                bordered: baseButton.bordered,
                circle: baseButton.circle,
                dashed: baseButton.dashed,
                disabled: baseButton.disabled,
                ghost: baseButton.ghost,
                loading: baseButton.loading,
                round: baseButton.round,
                size: baseButton.size
            },
            {
                default: () => baseButton.text
            }
        )
    }
}


// export let changeColumns = (obj: IPage) => {
//     obj.models[3].forms[0].options = obj.columns
//         .filter(c => c.key !== 'index')
//         .filter(c => c.key !== 'id')
//         .filter(c => c.key !== 'operation')
//         .map(c => {
//             return {
//                 label: c.title,
//                 value: c.key
//             }
//         })
//     obj.models[3].value['columnKeys'] = obj.columns
//         .filter(c => c.key !== 'index')
//         .filter(c => c.key !== 'id')
//         .filter(c => c.key !== 'operation')
//         .filter(c => c.exist)
//         .map(c => c.key)
// }

export interface IModel {
    disabled?: boolean
    inline?: boolean
    labelWidth?: number | 'auto' | string
    labelAlign?: 'left' | 'right'
    labelPlacement?: 'top' | 'left'
    model?: any
    rules?: any
    requireMarkPlacement?: 'left' | 'right' | 'right-hanging'
    size?: 'small' | 'medium' | 'large'

    formRef?: any
    formKey?: string
    exist?: boolean
    formStyle?: string
    formTitle?: string
    formInputs?: Array<BaseInput>
    modelOperations?: Array<BaseButton>
    formReset?: Function
}

export class BaseModel implements IModel {
    disabled: boolean = false
    inline: boolean = false
    labelWidth: number | 'auto' | string = 'auto'
    labelAlign: 'left' | 'right' = 'left'
    labelPlacement: 'top' | 'left' = 'top'
    model: any = {}
    rules: any = {}
    requireMarkPlacement: 'left' | 'right' | 'right-hanging' = 'left'
    size: 'small' | 'medium' | 'large' = 'medium'

    formRef: any = {}
    formKey: string
    exist: boolean = false
    formStyle: string = 'width: 50%'
    formTitle: string
    formInputs: Array<BaseInput>
    modelOperations: Array<BaseButton>
    formReset: Function

    constructor(formKey: string, formTitle: string, formInputs: Array<BaseInput>, modelOperations: Array<BaseButton>, page: BasePage) {
        this.formKey = formKey
        this.formTitle = formTitle
        this.formInputs = formInputs
        this.modelOperations = modelOperations
        this.formReset = () => {
            if ("search" === this.formKey) {
                let model: BaseModel = page.search
                if (model) {
                    model.formInputs.forEach(i => {
                        model.model[i.path] = i.defaultValue
                    })
                }
            } else {
                let model: BaseModel = page.models.filter(m => m.formKey === this.formKey)[0]
                if (model) {
                    model.formInputs.forEach(i => {
                        model.model[i.path] = i.defaultValue
                    })
                }
            }
            page.loadData()
        }
    }
}


export interface IMenu {
    key: string
    label: string | Function
    children: Array<IMenu> | null
    exist: boolean
    path: string
}

export let baseMenu = (): IMenu => {
    return {
        key: '',
        label: '',
        children: null,
        exist: true,
        path: ''
    }
}